<!doctype html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="_generated/main.css">
  <script src="https://distill.pub/template.v2.js"></script>
  <style>
    d-article section {
      contain: layout paint;
      margin: 0!important;
    }
    section > * {
      grid-column: text;
    }
    figure {
      contain: layout paint;
    }
    .app-container {
      border-top: solid 1px rgba(0, 0, 0, 0.2);
      border-bottom: solid 1px rgba(0, 0, 0, 0.2);
      grid-column: screen;
      height: 80vh;
      max-height: 400px;
      min-height: 300px;
      position: relative;
      box-shadow: 0 0 18px 4px rgba(0, 0, 0, 0.12);
      margin-top: 3em;
      margin-bottom: 3em;
      display: flex;
      contain: content;
      overflow: hidden;
    }
    @media (min-width: 900px) {
      .app-container {
        max-height: 1000px;
        min-height: 400px;
      }
    }
    d-title .app-container {
      margin-top: 1.5em;
    }
    .app-container > d-figure {
      display: block;
      margin: 0 0 0 8px;
      height: 100%;
      border-left: solid 1px rgba(0, 0, 0, 0.1);
      border-right: solid 1px rgba(0, 0, 0, 0.1);
      flex-grow: 1
    }
    d-title .app-container {
      margin-bottom: 0;
    }
  </style>
	<title>Activation Atlas</title>
</head>

<body>
<d-front-matter>
  <script type="text/json">{
  "title": "Activation Atlas",
  "description": "By using feature inversion to visualize millions of activations from an image classification network, we create an explorable activation atlas of features the network has learned and what concepts it typically represents.",
  "authors": [
    {
      "author": "Shan Carter",
      "authorURL": "https://shancarter.com/",
      "affiliation": "Google Brain Team",
      "affiliationURL": "https://g.co/brain"
		},
    {
			"author": "Zan Armstrong",
      "authorURL": "https://www.zanarmstrong.com/",
      "affiliation": "Google Accelerated Science",
      "affiliationURL": "https://ai.google/research/teams/applied-science/gas/"
    },
    {
			"author": "Ludwig Schubert",
      "authorURL": "https://schubert.io/",
      "affiliation": "OpenAI",
			"affiliationURL": "https://openai.com/"
    },
    {
			"author": "Ian Johnson",
      "authorURL": "https://github.com/enjalot",
      "affiliation": "Google Cloud",
      "affiliationURL": "https://cloud.google.com/"
    },
		{
			"author": "Chris Olah",
			"authorURL": "https://colah.github.io/",
			"affiliation": "OpenAI",
			"affiliationURL": "https://openai.com/"
		}
  ],
  "katex": {
    "delimiters": [
      {
        "left": "$",
        "right": "$",
        "display": false
      },
      {
        "left": "$$",
        "right": "$$",
        "display": true
      }
    ]
  }
  }</script>
</d-front-matter>


<div id="tooltip"></div>

<d-title>
  <h1 style="grid-column-end: page;">Exploring Neural Networks with Activation Atlases</h1>
  <p>By using feature inversion to visualize millions of activations from an image classification network, we create an explorable <em>activation atlas</em> of features the network has learned which can reveal how the network typically represents some concepts.</p>
  <figure class="app-container">
    <d-figure id="cover"></d-figure>
  </figure>
  <div class="figcaption" style="grid-column: text;margin-top: 2em;">
    Above, an <b>activation atlas</b> of the InceptionV1 vision classification network reveals many fully realized features, such as
    <a href="#" data-cover-poi=".85,.50,12">electronics</a>,
    <a href="#" data-cover-poi=".79,.67,9">buildings</a>,
    <a href="#" data-cover-poi=".59,.26,12">food</a>,
    <a href="#" data-cover-poi=".35,.10,10">animal ears</a>,
    <a href="#" data-cover-poi=".261,.437,12">plants</a>, and
    <a href="#" data-cover-poi=".238,.835,12">watery backgrounds</a>.
    Grid cells are labeled with the classification they most support.
    <d-footnote>More specifically, We show a linear approximation of the effect of these average activation vectors of a grid cell on the logits.</d-footnote> Grid cells are also sized according to the density of the number of activations that are averaged within. <a href="app.html">View full-screen version</a>
    <div style="margin-top: 8px; text-align: right;">
      <span data-notebook-url="https://colab.research.google.com/github/tensorflow/lucid/blob/master/notebooks/activation-atlas/activation-atlas-simple.ipynb"></span>
    </div>
  </div>
</d-title>

<script src="./_generated/main.min.js"></script>

<d-article>
<section class="base-grid">
  <h2 id="introduction">Introduction</h2>

  <p>Neural networks can learn to classify images more accurately than any system humans directly design. This raises a natural question: What have these networks learned that allows them to classify images so well?

  </p><p>Feature visualization is a thread of research that tries to answer this question by letting us “see through the eyes” of the network <d-cite key="erhan2009visualizing,olah2017feature,simonyan2013deep,nguyen2015deep,mordvintsev2015inceptionism,nguyen2016plug"></d-cite>. It began with research into <a href="https://distill.pub/2017/feature-visualization/">visualizing individual neurons</a> and trying to determine what they respond to. Because neurons don’t work in isolation, this led to applying feature visualization to <a href="https://distill.pub/2017/feature-visualization/#interaction">simple combinations of neurons</a>. But there was still a problem — what combinations of neurons should we be studying? A natural answer (foreshadowed by work on model inversion <d-cite key="mahendran2015understanding"></d-cite>) is to  <a href="https://distill.pub/2018/building-blocks/#ActivationGridSingle">visualize activations</a> <d-cite key="olah2018building"></d-cite>, the combination of neurons firing in response to a particular input.

  </p><p>These approaches are exciting because they can make the hidden layers of networks comprehensible. These layers are the heart of how neural networks outperform more traditional approaches to machine learning and historically, we’ve had little understanding of what happens in them<d-footnote>With the exception of the first hidden layer.</d-footnote>. Feature visualization addresses this by connecting hidden layers back to the input, making them meaningful.

  </p><p>Unfortunately, visualizing activations has a major weakness — it is limited to seeing only how the network sees a single input. Because of this, it doesn’t give us a big picture view of the network. When what we want is a map of an entire forest, inspecting one tree at a time will not suffice.

  </p><p>
    There are techniques which give a more global view, but they tend to have other downsides.
    For example, Karpathy's <a href="https://cs.stanford.edu/people/karpathy/cnnembed/">CNN codes visualization</a><d-cite key="karpathy2014codes"></d-cite>
    gives a global view of a dataset by taking each image and organizing them by their activation values from a neural network.
    Showing which images the model sees as similar does help us infer some ideas about what features the network is responding to,
    but feature visualization makes those connections much more explicit.
    Nguyen, et al <d-cite key="nguyen2016multifaceted"></d-cite> use t-SNE to make more diverse neuron visualizations,
    generating diverse starting points for the optimization process by clustering images in the t-SNE map.
    This reveals a broader picture of what the neuron detects but is still focused on individual neurons.
  </p>

  <p>In this article we introduce <em>activation atlases</em> to this quiver of techniques. (An example is shown at the top of this article.) Broadly speaking, we use a technique similar to the one in CNN codes, but instead of showing input data, we show feature visualizations of averaged activations. By combining these two techniques, we can get the advantages of each in one view — a global map seen through the eyes of the network.

  </p><p>In theory, showing the feature visualizations of the <a href="https://distill.pub/2017/feature-visualization/appendix/">basis neurons</a> would give us the global view of a network that we are seeking. In practice, however, neurons are rarely used by the network in isolation, and it may be difficult to understand them that way. As an analogy, while the 26 letters in the alphabet provide a basis for English, seeing how letters are commonly combined to make words gives far more insight into the concepts that can be expressed than the letters alone. Similarly, activation atlases give us a bigger picture view by showing common combinations of neurons.

  <figure id="overview" style="grid-column: page;"></figure>

  </p><p>
    These atlases not only reveal visual abstractions within a model, but later in the article we will show that they can reveal high-level misunderstandings in a model that can be exploited. For example, by looking at an activation atlas we will be able to see why a picture of a baseball can switch the classification of an image from “grey whale” to “great white shark”.
  </p>
  

  <figure id="adversarial-teaser">
  </figure>

  <p>Of course, activation atlases do have limitations. In particular, they're dependent on the distribution of the data we choose to sample activations from (in our examples, we use one million images chosen at random from the ImageNet dataset <d-cite key="deng2009imagenet"></d-cite> training data).  As a result, they will only show the activations that exist within the distribution of the sample data. However, while it’s important to be aware of these limitations — we’ll discuss them in much more depth later! — Activation Atlases still give us a new kind of overview of what neural networks can represent.

</p></section>

<section class="base-grid">

  <h2 id="looking-at-a-single-image">Looking at a Single Image</h2>

  <p>Before we dive into Activation Atlases, let’s briefly review how we use feature visualization to make activation vectors meaningful (“see through the network’s eyes”). This technique was introduced in <a href="https://distill.pub/2018/building-blocks/">Building Blocks</a> <d-cite key="olah2018building"></d-cite>, and will be the foundation of Activation Atlases.

  </p><p>
    Throughout this article, we’ll be focussing on a particular neural network: InceptionV1 <d-cite key="szegedy2015going"></d-cite>
    (also known as "GoogLeNet").
    When it came out, it was notable for <a href="http://www.image-net.org/challenges/LSVRC/2014/results#clsin">winning</a> the classification task in the 2014 ImageNet Large Scale Visual Recognition Challenge <d-cite key="deng2009imagenet,russakovsky2015imagenet"></d-cite>.
  </p>

  <p>
    InceptionV1 consists of a number of layers, which we refer to as "mixed3a", "mixed3b", "mixed4a", etc., and sometimes shortened to just "3a". Each layer successively builds on the previous layers. 
  </p>

  <figure style="grid-column: page;">
    <div id="model-overview"></div>
    <div class="figcaption">InceptionV1 builds up its understanding of images over several layers (see <a href="https://distill.pub/2017/feature-visualization/appendix/">overview</a> from <d-cite key="olah2017feature"></d-cite>). It was trained on ImageNet ILSVRC <d-cite key="deng2009imagenet"></d-cite>. Each layer actually has several component parts, but for this article we’ll focus on these larger groups.</div>
  </figure>

  <p>To visualize how InceptionV1 sees an image, the first step is to feed the image into the network and run it through to the layer of interest. Then we collect the activations — the numerical values of how much each neuron fired. If a neuron is excited by what it is shown, its activation value will be positive.

  </p><p>Unfortunately these vectors of activation values are just vectors of unitless numbers and not particularly interpretable by people. This is where <a href="https://distill.pub/2017/feature-visualization/">feature visualization</a> comes in.

  Roughly speaking, we can think of feature visualization as creating an idealized image of what the network thinks would produce a particular activation vector.  Whereas we normally use a network to transform an image into an activation vector, in feature visualization we go in the opposite direction. Starting with an activation vector at a particular layer, we create an image through an iterative optimization process.

  </p><p>Because InceptionV1 is a <a href="http://colah.github.io/posts/2014-07-Conv-Nets-Modular/">convolutional network</a>, there is not just one activation vector per layer per image.
  This means that the same neurons are run on each patch of the previous layer.
  Thus, when we pass an entire image through the network, each neuron will be evaluated hundreds of times, once for each overlapping patch of the image. We can consider the vectors of how much each neuron fired for each patch separately.

  <figure style="grid-column: page;">
    <div id="activation-grid"></div>
    <div style="text-align: right; margin-top: 8px;">
      <span data-notebook-url="https://colab.research.google.com/github/tensorflow/lucid/blob/master/notebooks/building-blocks/ActivationGrid.ipynb"></span>
    </div>
  </figure>

  </p><p>The result is a grid of feature visualizations, one for each patch. This shows us how the network sees different parts of the input image.

  <figure id="grid-detail" style="grid-column: page;"></figure>

  </p><h2 id="aggregating-multiple-images">Aggregating Multiple Images</h2>

  <p>Activation grids show how the network sees a single image, but what if we want to see more? What if we want to understand how it reacts to millions of images?

  </p><p>Of course, we could look at individual activation grids for those images one by one. But looking at millions of examples doesn’t scale, and human brains aren’t good at comparing lots of examples without structure. In the same way that we need a tool like a histogram in order to understand millions of numbers, we need a way to aggregate and organize activations if we want to see meaningful patterns in millions of them.

  </p><p>Let's start by collecting activations from one million images. We'll randomly select one spatial activation per image.<d-footnote>We avoid the edges due to boundary effects.</d-footnote> This gives us one million activation vectors. Each of the vectors is high-dimensional, perhaps 512 dimensions! With such a complex set of data, we need to organize and aggregate it if we want a big picture view.

  </p><p>Thankfully, we have modern dimensionality reduction techniques at our disposal. These algorithms, such as t-SNE <d-cite key="maaten2008visualizing"></d-cite> and UMAP <d-cite key="mcinnes2018umap-software"></d-cite>, can project high-dimensional data like our collection of activation vectors into useful 2D layouts, preserving some of the local structure of the original space. This takes care of organizing our activation vectors, but we also need to aggregate into a more manageable number of elements -- one million dots would be hard to interpret. We’ll do this by drawing a grid over the 2D layout we created with dimensionality reduction. For each cell in our grid, we average all the activations that lie within the boundaries of that cell, and use feature visualization to create an iconic representation.

  <figure style="grid-column: page;">
    <div id="process"></div>
    <div style="display: grid; grid-column-gap: 20px; grid-template-columns: 1fr 1fr 1fr;">
      <div class="figcaption">A randomized set of one million images is fed through the network, collecting one random spatial activation per image.</div>
      <div class="figcaption">The activations are fed through UMAP to reduce them to two dimensions. They are then plotted, with similar activations placed near each other.</div>
      <div class="figcaption">We then draw a grid and average the activations that fall within a cell and run feature inversion on the averaged activation. We also optionally size the grid cells according to the density of the number of activations that are averaged within.</div>
    </div>
    <div style="text-align: right; margin-top: 8px;">
      <span data-notebook-url="https://colab.research.google.com/github/tensorflow/lucid/blob/master/notebooks/activation-atlas/activation-atlas-simple.ipynb"></span>
    </div>
  </figure>

  </p><p>
    We perform feature visualization with the regularizations described in Feature Visualization <d-cite key="olah2017feature"></d-cite> (in particular, <a href="https://distill.pub/2017/feature-visualization/#regularizer-playground-robust">transformation robustness</a>).
    However, we use a slightly non-standard objective.
    Normally, to visualize a direction in activation space, $v$, one maximizes the dot product with the activation vector $h$ at a position: $h_{x,y} \cdot v$.
    We find it helpful to use an objective that emphasizes angle more heavily by multiplying the dot product by cosine similarity, leading to objectives of the following form:
    $\frac{(h_{x,y} \cdot v)^{n+1}}{(||h_{x,y}|| \cdot ||v||)^{n}}$.
    We also find that whitening the activation space to unstretch it can help improve feature visualization.
    We don't yet fully understand this phenomenon.
    A reference implementation of this can be seen in the attached notebooks, and more general discussion can be found in this <a href="https://github.com/tensorflow/lucid/issues/116">github issue</a>.
  </p>

  <p>
    For each activation vector, we also compute an <em>attribution</em> vector.
    The attribution vector has an entry for each class, and approximates the amount that the activation vector influenced the logit for each class.
    Attribution vectors generally depend on the surrounding context.
    We follow Building Blocks <d-cite key="olah2018building"></d-cite> in computing the attribution of the activation vector at a position, $h_{x,y}$, to a class logit, $\text{logit}_c$ as $h_{x,y} \cdot \nabla_{h_{x,y}} \text{logit}_c$.
    That is, we estimate that the effect of a neuron on a logit is the rate at which increasing the neuron affects the logit.
    This is similar to Grad-CAM <d-cite key="selvaraju2016grad"></d-cite>, but without the spatial averaging of the gradient.
    Instead, we reduce noise in the gradient by using a continuous relaxation of the gradient for max pooling in computing the gradient (as in <d-cite key="olah2018building"></d-cite>).
    (A detailed reference implementation can be found in <a href="https://colab.research.google.com/github/tensorflow/lucid/blob/master/notebooks/building-blocks/AttrSpatial.ipynb">this notebook</a>.)
    The attribution shown for cells in the activation atlas is the average of attribution vectors for activations in that cell.
  </p>

  <p>
    This average attribution can be thought of as showing what classes that cell tends to support, marginalizing over contexts.
    At early layers, the average attribution is very small and the top classes are fairly arbitrary because low-level visual features like textures tend to not be very discriminative without context.
  </p>

  <p>So, how well does this work? Well, let’s try applying it to InceptionV1 <d-cite key="szegedy2015going"></d-cite> at <a href="https://distill.pub/2017/feature-visualization/appendix/googlenet/4c.html">layer mixed4c</a>.


  <figure id="one-layer" style="grid-column: screen;">
  </figure>

  </p><p>This atlas can be a bit overwhelming at first glance -- there’s a lot going on! This diversity is a reflection of the variety of abstractions and concepts the model has developed. Let’s take a tour to examine this atlas in more depth.

  </p><p>If we look at the top-left of the atlas, we see images which look like animal heads. There is some differentiation between different types of animals, but it seems to be more a collection of elements of generic mammals -- eyes, fur, noses -- rather than a collection of different classes of animals. We've also added labels that show which class each averaged activation most contributes to. Please note, in some areas of a layer this early in the network these attribution labels can be somewhat chaotic. <d-footenote>In early layers the attribution vectors have a small magnitude since they don't have a consistent effect on the output.</d-footenote>

  <figure id="layer-annotation-1" style="grid-column: text/page;"></figure>

  </p><p>As we move further down we start to see different types of fur and the backs of four-legged animals.

  <figure id="layer-annotation-2" style="grid-column: text/page;"></figure>

  </p><p>Below this, we find different animal legs and feet resting on different types of ground.
  <figure id="layer-annotation-3" style="grid-column: text/page;"></figure>

  </p><p>Below the feet we start to lose any identifiable parts of animals, and see isolated grounds and floors. We see attribution toward environments like "sandbar" and also toward things that are found on the ground, like "doormat" or "ant".

  <figure id="layer-annotation-4" style="grid-column: text/page;"></figure>

  </p><p>These sandy, rocky backgrounds slowly blend into beaches and bodies of water. Here we see lakes and oceans, both above and below water. Though the network does have certain classes like "seashore", we see attribution toward many sea animals, without any visual references to the animals themselves. While not unexpected, it is reassuring to see that the activations that are used to identify the sea for the class "seashore" are the same ones used when classifying "starfish" or "sea lion". There is also no real distinction at this point between lakes and ocean -- "lakeside" and "hippopotamus" attributions are intermingled with "starfish" and "stingray".

  <figure id="layer-annotation-5" style="grid-column: text/page;"></figure>

  </p><p>Now let’s jump to the other side of the atlas, where we can see many variations of text detectors. These will be useful when identifying classes such as "menu", "web site" or "book jacket".

  <figure id="layer-annotation-6" style="grid-column: text/page;"></figure>

  </p><p>Moving upward, we see many variations of people. There are very few classes that specifically identify people in ImageNet, but people are present in lots of the images. We see attribution toward things people use ("hammer", "flute"), clothes that people wear ("bow tie", "maillot") and activities that people participate in ("basketball"). There is a uniformity to the skin color in these visualizations which we suspect is a reflection of the distribution of the data used for training. (You can browse the ImageNet training data by category online: <a href="http://image-net.org/synset?wnid=n04371430#">swimming trunks</a>, <a href="http://image-net.org/synset?wnid=n03188531">diaper</a>, <a href="http://image-net.org/synset?wnid=n02786058">band aid</a>, <a href="http://image-net.org/synset?wnid=n03676483">lipstick</a>, etc.)

  <figure id="layer-annotation-7" style="grid-column: text/page;"></figure>

  </p><p>And finally, moving back to the left, we can see round food and fruit organized mostly by colors -- we see attribution toward "lemon", "orange" and "fig".

  <figure id="layer-annotation-8" style="grid-column: text/page;"></figure>

  </p><p>We can also trace curved paths through this manifold that we've created. Not only are regions important, but certain movements through the space seem to correspond to human interpretable qualities. With the fruit, we can trace a path that seems to correlate with the size and number of fruits in the frame.

  <figure id="show-a-path-3" style="grid-column: text/page;"></figure>

  </p><p>Similarly, with people, we can trace a path that seems to correspond to how many people are in the frame, whether it's a single person or a crowd.

  <figure id="show-a-path-1" style="grid-column: text/page;"></figure>

  </p><p>With the ground detectors, we can trace a path from water to beach to rocky cliffs.

  <figure id="show-a-path-2" style="grid-column: text/page;"></figure>

  </p><p>In the plants region, we can trace a path that seems to correspond to how blurry the plant is. This could possibly be used to determine relative size of objects because of the typical focal lengths of cameras. Close up photos of small insects have more opportunity for blurry background foliage than photos of larger animals, like monkeys.

  <figure id="show-a-path-0" style="grid-column: text/page;"></figure>

  </p><p>It is important to note that these paths are constructed after the fact in the low-dimensional projection. They are smooth paths in this reduced projection but we don't necessarily know how the paths operate in the original higher-dimensional activation space.</p>

</section>
<section class="base-grid">

  <h2 id="looking-at-multiple-layers">Looking at Multiple Layers</h2>

  <p>In the previous section we focused on one layer of the network, mixed4c, which is in the middle of our network. Convolutional networks are generally deep, consisting of many layers that progressively build up more powerful abstractions. In order to get a holistic view, we must look at how the model’s abstractions develop over several layers.

  <figure style="display: grid; grid-column: page; grid-template-columns: 1fr 1fr 1fr; grid-gap: 20px;">
    <div style="width: 100%; grid-area: 1 / 1 / 2 / 4;" data-lazy-image-aspect-ratio="6.306" data-lazy-image="model2.svg" alt="model"></div>
  <div class="figcaption">In early layers (eg. <a href="”https://distill.pub/2017/feature-visualization/appendix/googlenet/3b.html”">mixed3b</a>), the network seems to represents textures and simple patterns.</div>
    <div class="figcaption"> By mid layers (eg. <a href="”https://distill.pub/2017/feature-visualization/appendix/googlenet/4c.html”">mixed4c</a>), icons evoke individual concepts like eyes, leaves, water, that are shared among many classes.</div>
    <div class="figcaption"> In the final layers (eg. <a href="”https://distill.pub/2017/feature-visualization/appendix/googlenet/5b.html”">mixed5b</a>), abstractions become more closely aligned with the output classes.</div>
  </figure>


  </p><p>To start, let's compare three layers from different areas of the network to try to get a sense for the different personalities of each -- one very early layer (<a href="”https://distill.pub/2017/feature-visualization/appendix/googlenet/3b.html”">mixed3b</a>), one layer from the middle (<a href="”https://distill.pub/2017/feature-visualization/appendix/googlenet/4c.html”">mixed4c</a>), and the final layer (<a href="”https://distill.pub/2017/feature-visualization/appendix/googlenet/5b.html”">mixed5b</a>) before the logits. We'll focus on areas of each layer that contribute to the classification of "cabbage".

  <style>
    .vertical-layer-comparison {
      display: grid;
      grid-column: page;
      grid-template-columns: 1fr 1fr 1fr;
      grid-gap: 16px 20px;
    }
    .vertical-layer-comparison h4 {
      margin-bottom: 0;
      padding-bottom: 4px;
      width: 100%;
      border-bottom: solid #CCC 1px;
    }
    .vertical-layer-comparison.progress {
      display: block;
      max-width: 704px;
      padding: 0 20px;
      margin: 0 auto;
    }
    .vertical-layer-comparison.progress > div {
      display: grid;
      grid-template-columns: 2.5fr 1fr;
      grid-gap: 20px;
      margin-bottom: 16px;
    }
    .vertical-layer-comparison.progress h4 {
      margin-top: 0;
      margin-bottom: 16px;
    }
    .vertical-layer-comparison.progress .figcaption {
      margin-top: 8px;
    }
  </style>


  <figure class="vertical-layer-comparison">
    <h4>Mixed3b</h4>
    <h4>Mixed4c</h4>
    <h4>Mixed5b</h4>
    <div id="plant-0"></div>
    <div id="plant-1"></div>
    <div id="plant-2"></div>
  </figure>

  

  </p><p>As you move through the network, the later layers seem to get much more specific and complex. This is to be expected, as each layer builds its activations on top of the preceding layer’s activations. The later layers also tend to have larger receptive fields than the ones that precede them (meaning they are shown larger subsets of the image) so the concepts seem to encompass more of the whole of objects.


  </p><p>There is another phenomenon worth noting: not only are concepts being refined, but new concepts are appearing out of combinations of old ones. Below, you can see how sand and water are distinct concepts in a middle layer, mixed4c, both with strong attributions to the classification of "sandbar". Contrast this with a later layer, mixed5b, where the two ideas seem to be fused into one activation.

  <figure class="vertical-layer-comparison">
    <h4 style="grid-area: 1 / 1 / 2 / 3; width: 100%;">Mixed4c</h4>
    <h4>Mixed5b</h4>
    <div id="water-0"></div>
    <div id="water-1"></div>
    <div id="water-2"></div>
  </figure>

  </p><p>Finally, if we zoom out a little, we can see how the broader shape of the activation space changes from layer to layer. By looking at similar regions in several consecutive layers, we can see concepts getting refined and differentiated — In mixed4a we see very vague, generic blob, which gets refined into much more specific "peninsulas" by mixed4e.</p>

  <figure style="grid-column: screen">
    <div class="vertical-layer-comparison progress">
      <div>
        <div data-lazy-image-aspect-ratio="1.7" data-lazy-image="progress-mixed4a.jpg" alt="mixed4a"></div>
        <div>
          <h4>Mixed4a</h4>
          <div class="figcaption">
            In mixed4a there is a vague "mammalian" area.
          </div>
        </div>
      </div>
      <div>
        <div data-lazy-image-aspect-ratio="1.7" data-lazy-image="progress-mixed4b.jpg" alt="mixed4b"></div>
        <div>
          <h4>Mixed4b</h4>
          <div class="figcaption">
            By mixed4b, animals and people have been disentangled, with some fruit and food emerging in the middle.
          </div>
        </div>
      </div>
      <div>
        <div data-lazy-image-aspect-ratio="1.7" data-lazy-image="progress-mixed4c.jpg" alt="mixed4c"></div>
        <div>
          <h4>Mixed4c</h4>
          <div class="figcaption">
            All the concepts are further refined and differentiated into small "peninsulas".
          </div>
        </div>
      </div>
      <div>
        <div data-lazy-image-aspect-ratio="1.7" data-lazy-image="progress-mixed4d.jpg" alt="mixed4d"></div>
        <div>
          <h4>Mixed4d</h4>
          <div class="figcaption">
            The specialization continues in mixed4d.
          </div>
        </div>
      </div>
      <div>
        <div data-lazy-image-aspect-ratio="1.7" data-lazy-image="progress-mixed4e.jpg" alt="mixed4e"></div>
        <div>
          <h4>Mixed4e</h4>
          <div class="figcaption">
            And further still in mixed4e.
          </div>
        </div>
      </div>
    </div>
  </figure>

  <p>Below you can browse many more of the layers of InceptionV1. You can compare the
  <a href="#" data-poi="curves">curved edge detectors of mixed4a</a> with the
  <a href="#" data-poi="cups">bowls and cups of mixed5b</a>. Mixed4b has some
  <a href="#" data-poi="patterns">interesting text and pattern detectors</a>, whereas mixed5a appears to use those to differentiate
  <a href="#" data-poi="text">menus from crossword puzzles from rulers</a>. In early layers, like mixed4b, you'll see things that have similar textures near each other, like
  <a href="#" data-poi="fabric">fabrics</a>. In later layers, you'll see
  <a href="#" data-poi="clothing">specific types of clothing</a>.

  <figure class="app-container">
    <d-figure id="all-layer-comparison"></d-figure>
  </figure>

  

</p></section>

<section class="base-grid">

  <h2 id="focusing-on-a-single-classification">Focusing on a Single Classification</h2>

  <p>Looking at an atlas of all activations can be a little overwhelming, especially when you're trying to understand how the network goes about ranking one particular class. For instance, let's investigate how the network classifies a "fireboat".

  <figure style="display: grid; grid-template-columns: 3fr 1fr; grid-gap: 20px;">
    <div data-lazy-image-aspect-ratio="1.335" data-lazy-image="fireboat-01.jpg" alt="fireboat"></div>
    <figcaption>An image labeled "fireboat" from ImageNet.</figcaption>
  </figure>

  </p><p>We'll start by looking at an atlas for the last layer, mixed5b. Instead of showing all the activations, however, we'll calculate the amount that each activation contributes toward a classification of "fireboat" and then map that value to the opacity of the activation icon.<d-footnote>In the case of mixed5b, determining this contribution is fairly straightforward because the relationship between activations at mixed5b and the logit values is linear. When there are multiple layers between our present one and the output -- and as a result, the relationship is non-linear -- it’s a little less clear what to do. In this article, we take the simple approach of forming a linear approximation of these future layers and use it to approximate the effect of our activations.</d-footnote> The areas that contribute a lot toward a classification of "fireboat" will be clearly visible, whereas the areas that contribute very little (or even contribute negatively) will be completely transparent.

  <figure id="focus-1" style="grid-column: screen;"></figure>

  </p><p>The layer we just looked at, mixed5b, is located just before the final classification layer so it seems reasonable that it would be closely aligned with the final classes. Let's look at a layer a little earlier in the network, say mixed4d, and see how it differs.

  <figure id="focus-2" style="grid-column: screen;"></figure>

  </p><p>Here we see a much different pattern.  If we look at some more input examples, this seems entirely reasonable. It's almost as if we can see a collection of the component concepts the network will use in later layers to classify "fireboat". Windows + crane + water = "fireboat".

  <figure style="display: grid; grid-template-columns: 1fr 1fr 1fr; grid-gap: 20px;">
    <div data-lazy-image-aspect-ratio="1.423" data-lazy-image="fireboat-10.jpg" alt="fireboat"></div>
    <div data-lazy-image-aspect-ratio="1.423" data-lazy-image="fireboat-02.jpg" alt="fireboat"></div>
    <div data-lazy-image-aspect-ratio="1.423" data-lazy-image="fireboat-03.jpg" alt="fireboat"></div>
  </figure>

  </p><p>One of the clusters, the one with windows, has strong attribution to "fireboat", but taken on its own, it has an even stronger attribution toward "streetcar". So, let's go back to the atlas at mixed4d, but isolate "streetcar" and compare it to the patterns seen for "fireboat". Let's look more closely at the four highlighted areas: the three areas we highlighted for fireboat plus one additional area that is highly activated for streetcars.

  <figure id="focus-3" style="grid-column: screen;"></figure>

  </p><p>If we zoom in, we can get a better look at what distinguishes the two classifications at this layer. (We've cherry-picked these examples for brevity, but you can explore all the layers and activations in detail in a explorable playground below.)

  <figure id="focus-3-table" style="grid-column: screen;"></figure>

  </p><p>If we look at a couple of input examples, we can see how buildings and water backgrounds are an easy way to differentiate between a "fireboat" and a "streetcar".

  <figure style="display: grid; grid-template-columns: 1fr 1fr; grid-gap: 10px 20px;">
    <div data-lazy-image-aspect-ratio="1.335" data-lazy-image="fireboat-01.jpg" alt="fireboat"></div>
    <div data-lazy-image-aspect-ratio="1.325" data-lazy-image="streetcar-01.jpg" alt="streetcar"></div>
    <figcaption>Images from ImageNet</figcaption>
  </figure>

  </p><p>By isolating the activations that contribute strongly to one class and comparing it to other class activations, we can see which activations are conserved among classes and which are recombined to form more complex activations in later layers. Below you can explore the activation patterns of many classes in ImageNet through several layers of InceptionV1. You can even explore negative attributions, which we ignored in this discussion.

  <figure class="app-container">
    <d-figure id="focus-playground"></d-figure>
  </figure>

</p></section>
<section class="base-grid">
  <h2 id="further-isolating-classes">Further Isolating Classes</h2>

  <p>Highlighting the class-specific activations in situ of a full atlas is helpful for seeing how that class relates to the full space of what a network "can see." However, if we want to really isolate the activations that contribute to a specific class we can remove all the other activations rather than just dimming them, creating what we'll call a <em>class activation atlas</em>. Similar to the general atlas, we run dimensionality reduction<d-footnote>For class activations we generally have better results from using t-SNE for the dimensionality reduction step rather than UMAP. We suspect it is because the data is much more sparse.</d-footnote> over the class-specific activation vectors in order to arrange the feature visualizations shown in the class activation atlas.

  <figure id="class-subset" style="grid-column: text;"></figure>

  </p><p>A class activation atlas gives us a much clearer view of which detectors the network is using to rank a specific class. In the "snorkel" example we can clearly see ocean, underwater, and colorful masks.

  </p><p>In the previous example, we are only showing those activations whose strongest attribution is toward the class in question. This will show us activations that contribute mostly to our class in question, even if their overall strength is low (like in background detectors). In some cases, though, there are strong correlations that we'd like to see (like fish with snorkelers). These  activations on their own might contribute more strongly to a different class than the one we're interested in, but their existence can also contribute strongly to our class of interest. For these we need to choose a different filtering method.</p>

  <figure id="class-filter-comparison" style="grid-column: screen;"></figure>

  <p>Using the magnitude filtering method, let's try to compare two related classes and see if we can more easily see what distinguishes them. (We could have instead used rank, or a combination of the two, but magnitude will suffice to show us a good variety of concepts).

  </p><div style="grid-column: page;">
    <figure id="class-comparison-2" style="grid-column: page;"></figure>
  </div>

  <p>It can be a little hard to immediately understand all the differences between classes. To help make the comparison easier, we can combine the two views into one. We'll plot the difference between the attributions of the "snorkel" and "scuba diver" horizontally, and use t-SNE <d-cite key="maaten2008visualizing"></d-cite> to cluster similar activations vertically.

  <figure id="class-gradient-snorkel" style="grid-column: text;"></figure>

  </p><p>In this comparison we can see some bird-like creatures and clear tubes on the left, implying a correlation with "snorkel", and some shark-like creatures and something round, shiny, and metallic on the right, implying correlation with "scuba diver" (This activation has a strong attribution toward the class "steam locomotive"). Let's take an image from the ImageNet dataset labeled as "snorkel" and add something that resembles this icon to see how it affects the classification scores.

  <figure id="snorkel-scuba-diver" style="grid-column: page"></figure>

  </p><p>The failure mode here seems to be that the model is using its detectors for the class "steam locomotive" to identify air tanks to help classify "scuba diver". We'll call these "multi-use" features -- detectors that react to very different concepts that are nonetheless visually similar. Let’s look at the differences between a “grey whale” and a “great white shark” to see another example of this issue.

  <figure id="class-gradient-shark" style="grid-column: text;"></figure>
  
  </p><p>In this example we see another detector that seems to be playing two roles: detecting red stitching on a baseball and a sharks's white teeth and pink inner mouth. This detector also shows up in the <a href="#focus-playground">activation atlas at layer mixed5b filtered to "great white shark"</a> and its attribution points towards all sorts of balls, the top one being "baseball".
    

   </p><p>Let’s add a picture of a baseball to a picture of a “grey whale” from ImageNet and see how it effects the classification.

  <figure id="shark-grey-whale" style="grid-column: page"></figure>

  </p><p>The results follow the pattern in previous examples pretty closely.
    Adding a small-sized baseball does change the top classification to “great white shark”, and as it gets bigger it overpowers the classification, so the top slot goes to “baseball”.

  </p><p>Let's look at one more example: "frying pan" and "wok".

  <figure id="class-gradient-frying-pan" style="grid-column: text"></figure>

  </p><p>One difference stands out here — the type of related foods present. On the right we can clearly see something resembling noodles (which have a strong attribution toward the class "carbonara"). Let's take a picture from ImageNet labeled as "frying pan" and add an inset of some noodles.

  <figure id="frying-pan-wok" style="grid-column: page"></figure>

  </p><p>Here the patch was not as effective at lowering the initial classification, which makes sense since the noodle-like icons were plotted more toward the center of the visualization thus having less of a difference in attribution. We suspect that the training set simply contained more images of woks with noodles than frying pans with noodles.

  </p><h3>Testing dozens of patches on thousands of images</h3>

  <p>So far we've only shown single examples of these patches. Below we show the result of ten sample patches (each set includes the one example we explored above), run on 1,000 images from the ImageNet training set for the class in question. While they aren't effective in all cases, they do flip the image classification to the target class in about 2 in 5 images. The success rate reaches about 1 in 2 images if we also allow to position the patch in the best of the four corners of the image (top left, top right, bottom left, bottom right) at the most effective size. To ensure our attack isn't just blocking out evidence for the original class, we also compare each attack to a random noise image patch.</p>
  
  <style>
    #adversarial-analysis {
      display: none;
      grid-column: text;
      margin-bottom: 0;
    }
    #adversarial-analysis table {
      width: 100%;
      text-align: right;
    }
    #adversarial-analysis table th {
      vertical-align: initial;
    }
    #adversarial-analysis table th .figcaption {
      display: block;
      font-weight: initial;
    }
    #adversarial-analysis table th img {
      width: initial;
    }
    #adversarial-analysis table .detail {
      /* padding-left: 1em; */
      font-size: 85%;
      color: rgba(0, 0, 0, 0.6);
    }
    #adversarial-analysis table .synset {
      font-family: monospace;
      white-space: nowrap;
    }
    #adversarial-analysis table .from,
    #adversarial-analysis table .to {
      white-space: nowrap;
    }
    #adversarial-analysis table .overall {
      font-weight: bold;
    }
    @supports (font-variant-numeric: tabular-nums) {
      #adversarial-analysis table {
          font-variant-numeric: tabular-nums;
      }
    }
  </style>  


  

  <figure id="patch-examples" style="grid-column: text;"></figure>

  <p>
    Our "attacks" can be seen as part of a larger trend (eg. <d-cite key="DBLP:journals/corr/abs-1712-09665,kurakin2016adversarial,engstrom2017rotation,brown2018unrestricted"></d-cite>) of researchers
    exploring input attacks on models other than the traditional epsilon ball adversarial examples <d-cite key="szegedy2013intriguing"></d-cite>.
    In many ways, our attacks are most similar to adversarial patches <d-cite key="DBLP:journals/corr/abs-1712-09665"></d-cite>, which also add a small patch to the input image.
    From this perspective, adversarial patches are far more effective, working much more reliably. Instead, we see our attacks as interesting because they are synthesized by humans from their understanding of the model,
    and seem to be attacking the model at a higher level of abstraction.
  </p>

  <p>
    We also want to emphasize that not all class comparisons reveal these type of patches and not all icons in the visualization have the same (or any) effectiveness and we've only tested them on one model. If we wanted to find these patches more systematically, a different approach would most likely be more effective. However, the class activation atlas technique was what revealed the existence of these patches before we knew to look for them. If you'd like to explore your own comparisons and search for your own patches, we've provided a notebook to get you started: <span data-notebook-url="https://colab.research.google.com/github/tensorflow/lucid/blob/master/notebooks/activation-atlas/activation-atlas-adversarial.ipynb"></span>
  </p>
</section>

<section class="base-grid">
  <h2 id="conclusion-and-future-work">Conclusion and Future Work</h2>

  <p>Activation atlases give us a new way to peer into convolutional vision networks. They give us a global, hierarchical, and human-interpretable overview of concepts within the hidden layers. Not only does this allow us to better see the inner workings of these complicated systems, but it's possible that it could enable new interfaces for working with images.

  </p><h3>Surfacing Inner Properties of Models</h3>

  <p>The vast majority of neural network research focuses on quantitative evaluations of network behavior. How accurate is the model? What’s the precision-recall curve?

  </p><p>While these questions can describe how the network behaves in specific situations, it doesn’t give us a great understanding of <em>why</em> it behaves the way it does. To truly understand why a network behaves the way it does, we would need to fully understand the rich inner world of the network — it’s hidden layers. For example, understanding better how InceptionV1 builds up a classifier for a fireboat from component parts in mixed4d can help us build confidence in our models and can surface places where it isn’t doing what we want.

  </p><p>Engaging with this inner world also invites us to do deep learning research in a new way. Normally, each neural network experiment gives only a few bits of feedback — whether the loss went up or down — to inform the next round of experiments. We design architectures by almost blind trial and error, guided by vague intuitions that we build up over years. In the future, we hope that researchers will get rich feedback on what each layer in their model is doing in a way that will make our current approach seem like stumbling in the dark.

  </p><p>Activation atlases, as they presently stand, are inadequate to really help researchers iterate on models, in part because they aren’t comparable. If you look at atlases for two slightly different models, it’s hard to take away anything. In future work, we will explore how similar visualizations can compare models, showing similarities and differences beyond error rates.


  </p><h3>New interfaces</h3>

  <p>Machine learning models are usually deployed as black boxes that automate a specific task, executing it on their own. But there’s a growing sense that there might be an alternate way for us to relate to them: that instead of increasingly automating a task, they could be used more directly by a person. One vision of this augmentation that we find particularly compelling is the idea that the internal representations neural networks learn can be repurposed as tools <d-cite key="carter2017using,olah2015visualizing,johnson2018machine"></d-cite>. Already, we’ve seen exciting demonstrations of this in images
  <d-cite key="isola2017image,loh2017toposketch,zhu2016generative"></d-cite>
  and music
  <d-cite key="mccurry2018latent,roberts2018hierarchical"></d-cite>
  .

  </p><p>We think of activation atlases as revealing a machine-learned alphabet for images — a collection of simple, atomic concepts that are combined and recombined to form much more complex visual ideas. In the same way that we use word processors to turn letters into words, and words into sentences, we can imagine a tool that would allow us to create images from a machine-learned language system for images. Similar to GAN painting <d-cite key="bau2018gandissect"></d-cite>, imagine using something like an activation atlas as a palette -- one could dip a brush into a “tree” activation and paint with it. A palette of concepts rather than colors.

  </p><p>While classification models are not generally thought of as being used to generate images, techniques like <d-cite key="mordvintsev2015inceptionism">deep dream</d-cite> has shown that this is entirely possible. In this particular instance, we imagine constructing a grid of activations by selecting them from an atlas (or some derivation), then optimizing an output image that would correspond to the user's constructed activation matrix.

  </p><p>Such a tool would not necessarily be limited to targeting realistic images either. Techniques like style transfer <d-cite key="gatys2015neural"></d-cite> have shown us that we can use these vision networks to create nuanced visual expression outside the explicit distribution of visual data it was trained on. We speculate that activation atlases could be helpful in manipulating artistic styles without having to find an existing reference image, or they could help in guiding and modifying automated style transfer techniques.

  </p><p>We could also use these atlases to query large image datasets. In the same way that we probe large corpuses of text with  words, we could, too, use activation atlases to find types of images in large image datasets. Using words to search for something like a “tree” is quite powerful, but as you get more specific, human language is often ill-suited to describe specific visual characteristics. In contrast, the hidden layers of neural networks are a language optimized for the sole purpose of representing visual concepts. Instead of using the proverbial thousand words to uniquely specify the image one is seeking, we can imagine someone using the language of the activation atlas.

  </p><p>And lastly, we can also liken activation atlases to histograms. In the same way that traditional histograms give us good summaries of large datasets, activation atlases can be used to summarize large numbers of images.

  </p><p>In the examples in this article we used the same dataset for training the model as we did for collecting the activations. But, if we use a different dataset to collect the activations, we could use the atlas as a way of inspecting an unknown dataset. An activation atlas could show us a histogram of <em>learned concepts</em> that exist within the images. Such a tool could show us the semantics of the data and not just visual similarities, like showing histograms of common pixel values.

  </p><p>While we are excited about the potential of activation atlases, we are even more excited at the possibility of developing similar techniques for other types of models. Imagine having an array of machine learned, but human interpretable, languages for images, audio and text.
</p></section>

</d-article>

<d-appendix>
<h3>Technical Notes and Limitations</h3>
  <p>In this section we note some of the limits and pitfalls that we've noticed while developing and working with activation atlases.</p>

  <h4>Sampling based</h4>

  <p>Activation Atlases are a sample-based method which can only show a manifold of sampled activations. First, the dataset from which those activations are sampled from needs to come from the same distribution as the one that we are interested in. In this article we sample from the training set because we are interested in what the model has learned to recognize. Second, we need to provide enough samples to span the full manifold we want to observe. In this article we generally used one million activations but we found that 100,000 activations was often sufficient.

  <figure id="samples" style="grid-column: page;"></figure>

  </p><h4>Doesn’t Surface Compositionality</h4>

  <p>Neural network activations have an underlying compositional, combinatorial structure. We can mix together a couple hundred basis neurons to get any activation vector. Unfortunately, this has the problem of being an exponentially large space and hard to find the interesting activations. Activation Atlases solve this problem by sampling the interesting activation vectors, but completely lose the original compositional structure.

  </p><p>By not surfacing the compositional structure, activation atlases don’t really support us thinking about novel combinations of directions. They also necessarily can’t show a lot of connections between different parts of the atlas, and have to collapse local structure down to two dimensions.

  </p><p>Surfacing compositionality is deeply connected to the high-dimensional nature of the original space. As a result, it’s naturally hard to do in 2D. That said, it may be possible to partially surface compositionality, like the <a href="https://distill.pub/2017/feature-visualization/#linear-combinations">neuron addition diagram</a> in Feature Visualization <d-cite key="olah2017feature"></d-cite> did. Another early prototype is a <a href="https://colab.research.google.com/github/tensorflow/lucid/blob/master/notebooks/misc/neuron_interaction_grids.ipynb">neuron activation grid</a>. We vaguely suspect that there may be a way to thread the needle with clever use of matrix factorization, but we do not yet know how.


  </p><h4>No alignment between layers</h4>

  <p>There's no way to link two views together. For instance, when looking at two layers side-by-side, similar features appear in random locations.

  </p><h4>Computationally expensive</h4>

  <p>It's computationally expensive. While it depends on many factors, activation atlases generally take somewhere between several minutes and several hours, end to end.

  </p><h4>Dependency on hyperparameters</h4>

  <p>Because it is based on dimensionality reduction, the final output can be very sensitive to the hyperparameters chosen for the reduction step. UMAP and t-SNE are both reasonable choices and each could also produce different results.

  </p><p>Because the choice of a grid size is somewhat arbitrary, much like choosing a histogram bin size <d-cite key="aranm2017exploring"></d-cite>, your choice of grid size will determine the effectiveness of the final output. Choosing the wrong bin size can sometimes <em>hide</em> important features in the averages. In some of the later examples we bind this value to the zoom level so the detail of the visualizations dynamically change as you zoom in. A more principled clustering method might be better.

  <figure id="class-grids" style="grid-column: page;"></figure>

  </p><h4>Dimensionality reduction vs clustering</h4>

  <p>One might think that a true clustering algorithm, like k-means, might produce a more robust decomposition of the activation manifold. After all, centroids produced by such an algorithm are by definition close to clusters of activations the network produces, a property that discretizing the dimensionality-reduced activations doesn’t guarantee. We experimented with different clustering techniques such as k-means, spherical k-means, and DBSCAN. However, the images produced by visualizing the resulting centroids were subjectively worse and less interpretable than the technique described in this article. Also, dimensionality reduction followed by 2D binning allows for multiple levels of detail while preserving spatial consistency, which is necessary for making atlasses zoomable. Thus, we preferred that method over clustering in this article -- but finding tradeoffs between these techniques remains an open question.</p>

  <h3 id="author-contributions">Author Contributions</h3>
  <p>Shan Carter wrote the majority of the article and performed most of the experiments. Zan Armstrong helped with the interactive diagrams and the writing. Ludwig Schubert provided technical help throughout and performed the numerical analysis of the manual patches. Ian Johnson provided inspiration for the original idea and advice throughout. Chris Olah provided essential technical contributions and substantial writing contributions throughout.</p>
  <h3 id="acknowledgements">Acknowledgments</h3>
  <p>Thanks to Kevin Quealy and Sam Greydanus for substantial editing help. Thanks to Colin Raffel, Arvind Satyanarayan, Alexander Mordvintsev, and Nick Cammarata for additional feedback during development. </p>
  <p>We're also very grateful to Phillip Isola for stepping in as acting Distill editor for this article, and to our reviewers who took time to give us feedback, significantly improving our paper.</p>
  <p>The photo used to illustrate a sub-manifold in the introduction was taken by <a href="https://unsplash.com/photos/_STiCuGSxa8">Alexandru-Bogdan Ghita</a>.</p>


   <h3>Discussion and Review</h3>
  <p>
    <a href="https://github.com/distillpub/post--activation-atlas/issues/2">Review 1 - Anonymous </a><br>
    <a href="https://github.com/distillpub/post--activation-atlas/issues/3">Review 2 - Anonymous </a><br>
    <a href="https://github.com/distillpub/post--activation-atlas/issues/4">Review 3 - David Bau </a><br>
  </p>
	<d-footnote-list></d-footnote-list>
  <d-citation-list></d-citation-list>
</d-appendix>

<d-bibliography src="bibliography.bib"></d-bibliography>

</body>
